
import { Editor, FileSystemAdapter, Notice } from "obsidian";
import { exec } from "child_process";
import Toolbox from "./main";
import * as fs from "fs"
import * as path from "path"

const imageTypes = ["png", "jpg", "jpeg", "gif", "bmp", "tif", "tiff", "webp"];

export function uploadImage(plugin: Toolbox) {
    plugin.app.workspace.on('editor-paste', (evt: ClipboardEvent, editor: Editor) => {
        const types = evt.clipboardData?.types
        if (types == undefined || types.length == 0) {
            return;
        }
        console.debug("receive file types:", types)
        const type = types[0]
        if (!(type == "Files" || type.startsWith("image/"))) {
            return;
        }
        const files = evt.clipboardData?.files
        if (files == undefined || files.length == 0) {
            return;
        }
        evt.preventDefault()
        for (let index = 0; index < files.length; index++) {
            const file = files[index]
            if (!file) {
                continue
            }
            const isImg = isImageFile(file.name)
            let fileName = file.name
            if (isImg) {
                fileName = `Image_${new Date().getTime()}.${fileSuffix(file.name)}`
            }
            const result = upload(plugin, file, fileName)
            result.then((url) => {
                if (isImg) {
                    editor.replaceRange(`![${fileName}](${url})`, editor.getCursor());
                } else {
                    editor.replaceRange(`[${fileName}](${url})`, editor.getCursor());
                }
            }).catch((err) => {
                new Notice(`file upload failed:${err.message}`)
            });
        }
    });
}

function fileSuffix(fileName: string): string {
    const point = fileName.lastIndexOf('.')
    if (point == -1) {
        return ""
    }
    return fileName.substring(point + 1)
}

function isImageFile(fileName: string): boolean {
    if (!fileName) {
        return false
    }
    const fileExt = fileSuffix(fileName).toLocaleLowerCase()
    return imageTypes.includes(fileExt)
}


async function upload(plugin: Toolbox, file: File, fileName: string): Promise<string> {
    console.debug("upload file:", fileName, file.name)
    const basePath = (plugin.app.vault.adapter as FileSystemAdapter).getBasePath()
    const command = plugin.settings.uploader || "uploader.exe"
    const tmpFile = path.join(basePath, fileName)
    const arrayBuffer = await file.arrayBuffer()
    const buffer = Buffer.from(new Uint8Array(arrayBuffer));
    try {
        fs.writeFileSync(tmpFile, buffer)
        return await execCommand(command + " " + tmpFile);
    } catch (error) {
        new Notice(`error writing file:${error}`)
        return ""
    } finally {
        try {
            fs.rmSync(tmpFile, { force: true })
        } catch (error) {
            console.error("fialed to delete tmp file:", tmpFile)
        }
    }
}

async function execCommand(command: string): Promise<string> {
    console.debug("exec command:", command)
    return new Promise((resolve, reject) => {
        exec(command, (error, stdout, stderr) => {
            if (error) {
                new Notice(`exec command ${error.message}`)
                reject(error)
                return
            }
            if (stdout) {
                resolve(stdout.trim())
                return
            }
            if (stderr) {
                new Notice(`exec command ${stderr}`)
                reject(new Error(stderr))
                return
            }
        })
    });
}